package com.informa.unitils.datasetfactories;

import static com.informa.java.util.CollectionUtils.asList;

import java.io.File;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.dbunit.dataset.Column;
import org.dbunit.dataset.DataSetException;
import org.dbunit.dataset.IDataSet;
import org.dbunit.dataset.ITable;
import org.dbunit.dataset.ReplacementDataSet;
import org.unitils.dbunit.datasetfactory.impl.MultiSchemaXmlDataSetFactory;
import org.unitils.dbunit.util.MultiSchemaDataSet;

import com.informa.unitils.datasetfactories.valuemappers.LocationBytesMapper;
import com.informa.unitils.datasetfactories.valuemappers.ValueMapper;

public class DynamicDatasetFactory extends MultiSchemaXmlDataSetFactory {

	private List<? extends ValueMapper> mappers = asList(new LocationBytesMapper());
	private Map<String,String> replacementSubstrings = new HashMap<String, String>();

	@Override
	public MultiSchemaDataSet createDataSet(File... dataSetFiles) {
		MultiSchemaDataSet multiDataset = super.createDataSet(dataSetFiles);

		for(String schema : multiDataset.getSchemaNames()) {
			multiDataset.setDataSetForSchema(schema, buildReplacement(multiDataset.getDataSetForSchema(schema)));
		}

		return multiDataset;

	}

	protected List<? extends ValueMapper> getMappers() {
		return mappers;
	}

	private IDataSet buildReplacement(IDataSet dataSet) {
		try {
			return new ReplacementDataSet(dataSet, buildReplacementObjects(dataSet), replacementSubstrings);
		} catch (DataSetException e) {
			throw new RuntimeException(e);
		}
	}

	@SuppressWarnings("deprecation")
	private Map<Object,Object> buildReplacementObjects(IDataSet dataSet) throws DataSetException {

		Map<Object,Object> replacementObjects = new HashMap<Object, Object>();
		for(ITable table : dataSet.getTables()) {
			for(int row = 0; row < table.getRowCount(); row++) {
				for(Column column : table.getTableMetaData().getColumns()) {

					String value = table.getValue(row, column.getColumnName()).toString();

					boolean isPlaceHolder = value.startsWith("${") && value.endsWith("}");
					if (isPlaceHolder) {
						replacementObjects.put(value, replacementFor(value));
					}

				}
			}
		}

		return replacementObjects;

	}

	private Object replacementFor(String placeHolder) {

		String value = placeHolder.substring(2,placeHolder.length() - 1);

		for(ValueMapper mapper : getMappers()) {
			if (mapper.handles(value)) return mapper.map(value);
		}

		return placeHolder;
	}

}
